/*
	bin2mot converts a binary file to Motorola hex.
	Copyright (C) 2012  pioneer suntec
	2012/02/06 leichang
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define	BYTE_OF_1M			(1024*1024)
#define REC_LINE_SIZE		(0x20)
#define MAX_LINE_SIZE		(256)

typedef enum{
	FALSE = 0
,	TRUE
}boolean;

typedef enum{
	MOTREC_MODE_S0 = 0
,	MOTREC_MODE_S1
,	MOTREC_MODE_S2
,	MOTREC_MODE_S3
,	MOTREC_MODE_S5 = 5
,	MOTREC_MODE_S7 = 7
,	MOTREC_MODE_S8
,	MOTREC_MODE_S9
,	MOTREC_MODE_UNKNOWN = 0xFF
}MOTREC_MODE;

void usage(void)
{
	fprintf(stderr, 
			"usage:\n"
			"bin2mot.exe -i InputFile -o OutputFile [-s1]\n"
			"\t-i InputFile  : Binary file name.\n"
			"\t-o OutputFile : Mot file name.\n"
			"\t-s1           : Mot file S1 or S2 or S3.\n");
	exit(1);
}

int main (int argc, char *argv[])
{
	int i;
	FILE *filein;	/* input files */
	FILE *fileout;	/* output files */
	char MotLine[MAX_LINE_SIZE];	/* a line of mot file */
	char RecData[REC_LINE_SIZE*2+1];
	char *pInputFile = NULL;	/* point to input file name */
	char *pOutputFile = NULL;	/* point to output file name */
	MOTREC_MODE ucMotRecMode = MOTREC_MODE_UNKNOWN;
	unsigned long ulRecAddress = 0;
	unsigned char checksum;
	int ucRead = 0;

	fprintf(stdout, "bin2mot v1.0.0, Copyright (C) 2012 Pioneer Suntec.\n");

	if( 1 == argc )
	{
		usage();
		exit(1);
	}

	/* Analys parameter */
	for( i = 1; i < argc; i++ )
	{
		if( '-' == argv[i][0] )
		{
			switch( tolower(argv[i][1]) )
			{
				case 'i':
					if( argv[i][2] != '\0' )
					{
						usage();
					}
					else
					{
						pInputFile = argv[++i];
					}
					break;
					
				case 'o':
					if( argv[i][2] != '\0' )
					{
						usage();
					}
					else
					{
						pOutputFile = argv[++i];
					}
					break;
					
				case 's':
					if( argv[i][3] != '\0' )
					{
						usage();
					}
					else
					{
						switch( argv[i][2] )
						{
							case '1':
								ucMotRecMode = MOTREC_MODE_S1;
								break;

							case '2':
								ucMotRecMode = MOTREC_MODE_S2;
								break;

							case '3':
								ucMotRecMode = MOTREC_MODE_S3;
								break;

							case '0':
							case '5':
							case '7':
							case '8':
							case '9':
								fprintf(stdout, "Invalid record type \'%s\'!\n", argv[2]);
								usage();
								exit(1);
								break;

							default:
								fprintf(stdout, "Invalid record type \'%s\'!\n", argv[2]);
								usage();
								exit(1);
								break;
						}
					}
					break;
					
				default:
					usage();
					break;
			}
		}
	}

	if( pInputFile == NULL )
	{
		fprintf(stderr, "No input file name!\n");
		usage();
		exit(1);
	}

	if( NULL == pOutputFile )
	{
		fprintf(stderr, "No output file name!\n");
		usage();
		exit(1);
	}
	
	filein = fopen(pInputFile, "rb");
	if( NULL == filein )
	{
		fprintf(stderr, "Input file %s cannot be opened.", pInputFile);
		exit(1);
	}

	fileout = fopen(pOutputFile, "wb");
	if( fileout == NULL )
	{
		fprintf(stderr, "Output file %s cannot be opened.", pOutputFile);
		fclose (filein);
		exit(1);
	}

	if( MOTREC_MODE_UNKNOWN == ucMotRecMode )
	{
		long flen = 0;
		
		/* get file length */
		fseek(filein, 0L, SEEK_END);
		flen = ftell(filein);
		fseek(filein, 0L, SEEK_SET);
		
		if( flen <= 0x10000 )
		{
			ucMotRecMode = MOTREC_MODE_S1;
		}
		else if( flen <= 0x1000000 )
		{
			ucMotRecMode = MOTREC_MODE_S2;
		}
		else
		{
			ucMotRecMode = MOTREC_MODE_S3;
		}
	}

	checksum = 0;
	ucRead = fgetc(filein);
	i = 0;
	
	/* Now read the file and process the lines. */
	/* Repeat until end of filein */
	while(!feof(filein) || (i>0))
	{
		unsigned char ucWriteSize;

		if( !feof(filein) )
		{
			sprintf(&RecData[i*2], "%02X", ucRead);
			checksum += ucRead;
		}
		else
		{
			i -= 1;	/* The last read char is 0xFF, it's invalide. */
		}
		if( ( ++i >= REC_LINE_SIZE ) || ( feof(filein) ) )
		{
			ucWriteSize = i;
			RecData[i*2] = '\0';
			switch( ucMotRecMode )
			{
				case MOTREC_MODE_S1:
					i += 3;
					checksum += i;
					checksum += (ulRecAddress >> 8);
					checksum += (ulRecAddress & 0xFF);
					checksum = 0xFF - checksum;
					sprintf(MotLine, "S%1X%02X%04X%s%02X\r\n", ucMotRecMode, i, ulRecAddress, RecData, checksum);
					break;
					
				case MOTREC_MODE_S2:
					i += 4;
					checksum += i;
					checksum += (ulRecAddress >> 16);
					checksum += (ulRecAddress >> 8);
					checksum += (ulRecAddress & 0xFF);
					checksum = 0xFF - checksum;
					sprintf(MotLine, "S%1X%02X%06X%s%02X\r\n", ucMotRecMode, i, ulRecAddress, RecData, checksum);
					break;
					
				case MOTREC_MODE_S3:
					i += 5;
					checksum += i;
					checksum += (ulRecAddress >> 24);
					checksum += (ulRecAddress >> 16);
					checksum += (ulRecAddress >> 8);
					checksum += (ulRecAddress & 0xFF);
					checksum = 0xFF - checksum;
					sprintf(MotLine, "S%1X%02X%08X%s%02X\r\n", ucMotRecMode, i, ulRecAddress, RecData, checksum);
					break;
					
				default:
					break;
			}
			
			/* length = head+len+addr+data+checksum+enter */
			fwrite(MotLine, 2, 1+1+i+1, fileout);
			
			i = 0;
			checksum = 0;
			ulRecAddress += ucWriteSize;
		}
		
		/* Read a char from input file. */
		ucRead = fgetc(filein);
	}

	sprintf(MotLine, "S804000000FB\r\n");
	fwrite(MotLine, 2, 7, fileout);

	fclose(filein);
	fclose(fileout);

	return 0;
}








